#include "pch.h"
#include "ParticleEmitter.h"

namespace mini
{
	CParticleEmitter::CParticleEmitter()
	{
		mParticelsContent.resize(mParticlesMaxCount * 6);
	}

	CParticleEmitter::~CParticleEmitter()
	{
		SafeRelease(mpParticleEmitterType);
	}

	void CParticleEmitter::setEmitterType(CParticleEmitterType* pType)
	{
		if (nullptr != pType)
		{
			if (mpParticleEmitterType != pType)
			{
				SafeRelease(mpParticleEmitterType);
				mpParticleEmitterType = pType;
				pType->AddRef();
			}
		}
	}

	void CParticleEmitter::initEmitterType(const std::string& szName)
	{
		auto pFun = CParticleEmitterFactory::getSinglePtr()->createEmitterFun(szName);
		if (nullptr != pFun)
		{
			mParticles = &pFun->mLivePartices;
			setEmitterType(pFun);
			lua_State* pLua = CScriptPlugin::getSinglePtr()->getLuaState();
			if (!CLuaBind::doFile(szName.c_str()))
			{
				throw "load file faile";
			}
			int iTop = lua_gettop(pLua);
			std::string szMaterial = CResourceManager::getSinglePtr()->getTableItem<const char*>(pLua, "emitter", "typePath");
			std::string szMesh = CResourceManager::getSinglePtr()->getTableItem<const char*>(pLua, "emitter", "meshPath");
		
			std::string szSpeed = CResourceManager::getSinglePtr()->getTableItem<const char*>(pLua, "emitter", "Speed");
			pFun->mSpeed = std::stoi(szSpeed);

			std::string szFrequency = CResourceManager::getSinglePtr()->getTableItem<const char*>(pLua, "emitter", "Frequency");
			mFrequency = std::stof(szFrequency);

			std::string szLiveTime = CResourceManager::getSinglePtr()->getTableItem<const char*>(pLua, "emitter", "LiveTime");
			auto&& strLiveTime = foundation::split(szLiveTime, ",");
			{
				pFun->mLiveTime.x = std::stoi(strLiveTime.front());
				pFun->mLiveTime.y = std::stoi(strLiveTime.back());
			}

			std::string szEmitCreateCount = CResourceManager::getSinglePtr()->getTableItem<const char*>(pLua, "emitter", "EmitCreateCount");
			auto&& strEmitCreateCount = foundation::split(szEmitCreateCount, ",");
			{
				pFun->mCreateCount.x = std::stoi(strEmitCreateCount.front());
				pFun->mCreateCount.y = std::stoi(strEmitCreateCount.back());
			}

			std::string szRange = CResourceManager::getSinglePtr()->getTableItem<const char*>(pLua, "emitter", "Range");
			auto&& strRange = foundation::split(szRange, ",");
			{
				std::vector<float> vec;
				for (auto& item : strRange)
				{
					vec.push_back(std::stof(item));
				}
				mRange.x = vec[0];
				mRange.y = vec[1];
				mRange.z = vec[2];
			}

			std::string szInitPos = CResourceManager::getSinglePtr()->getTableItem<const char*>(pLua, "emitter", "InitPos");
			auto&& strInitPos = foundation::split(szInitPos, ",");
			{
				std::vector<float> vec;
				for (auto& item : strInitPos)
				{
					vec.push_back(std::stof(item));
				}
				if (vec[0] > 0.5f)
				{
					pFun->mRandomPos.x = vec[1];
					pFun->mRandomPos.y = vec[2];
					pFun->mRandomPos.z = vec[3];
				}
			}

			std::string szInitScale = CResourceManager::getSinglePtr()->getTableItem<const char*>(pLua, "emitter", "InitScale");
			auto&& strInitScale = foundation::split(szInitScale, ",");
			{
				std::vector<float> vec;
				for (auto& item : strInitScale)
				{
					vec.push_back(std::stof(item));
				}
				if (vec[0] > 0.5f)
				{
					pFun->mRandomScale.x = vec[1];
					pFun->mRandomScale.y = vec[2];
					pFun->mRandomScale.z = vec[3];
				}
			}

			std::string szInitRotation = CResourceManager::getSinglePtr()->getTableItem<const char*>(pLua, "emitter", "InitRotation");
			auto&& strInitRotation = foundation::split(szInitRotation, ",");
			{
				std::vector<float> vec;
				for (auto& item : strInitRotation)
				{
					vec.push_back(std::stof(item));
				}
				if (vec[0] > 0.5f)
				{
					pFun->mRandomRotation.x = vec[1];
					pFun->mRandomRotation.y = vec[2];
					pFun->mRandomRotation.z = vec[3];
				}
			}

			std::string szSize = CResourceManager::getSinglePtr()->getTableItem<const char*>(pLua, "emitter", "Size");
			auto&& strSize = foundation::split(szSize, ",");
			{
				std::vector<float> vec;
				for (auto& item : strSize)
				{
					vec.push_back(std::stof(item));
				}
				pFun->mParticleSize.x = vec[0];
				pFun->mParticleSize.y = vec[1];
				pFun->mParticleSize.z = vec[2];
			}

			lua_settop(pLua, iTop);

			if (szMesh.length() < 2)
			{
				if (initialiseMaterial(szMaterial))
				{
					if (mpMeshUnits.size() == 1)
					{
						CMesh* pMesh = new CMesh();
						if (nullptr != pMesh)
						{
							pMesh->fillVertexBuffer(&mParticelsContent[0], mParticlesMaxCount * 6 * sizeof(VertexVTC), sizeof(VertexVTC), D3D11_USAGE_DYNAMIC);
							std::vector<INT32> indices;
							int nIndice = mParticlesMaxCount * 6;
							indices.resize(nIndice);
							for( int i = 0; i < nIndice; ++i )
							{
								indices[i] = i;
							}
							pMesh->fillIndexBuffer(&indices[0], nIndice * sizeof(INT32), sizeof(INT32));
							mpMeshUnits.front()->bindMesh(pMesh);
						}
						SafeRelease(pMesh);
						
						pFun->mMaxParticles = mParticlesMaxCount;
						for (int i = 0; i < mParticlesMaxCount; ++i)
						{
							pFun->mFreePartices.push_back(new ParticleCell());
						}
					}
				}
			}
		}
	}

	void CParticleEmitter::update(float fDeltaTime)
	{
		if (nullptr != mpParticleEmitterType)
		{
			eEmitter(fDeltaTime);
			mpParticleEmitterType->update(fDeltaTime);
			mParticelsContent.resize(mParticles->size() * 6);
			int i = 0;
			for (auto item : *mParticles)
			{
				// Bottom left.
				mParticelsContent[i].position = CPoint3F(item->pos.x - mpParticleEmitterType->mParticleSize.x, item->pos.y - mpParticleEmitterType->mParticleSize.y, item->pos.z);
				mParticelsContent[i].texture = CPoint2F(0.0f, 1.0f);
				mParticelsContent[i].color = item->color;
				i++;

				// Top left.
				mParticelsContent[i].position = CPoint3F(item->pos.x - mpParticleEmitterType->mParticleSize.x, item->pos.y + mpParticleEmitterType->mParticleSize.y, item->pos.z);
				mParticelsContent[i].texture = CPoint2F(0.0f, 0.0f);
				mParticelsContent[i].color = item->color;
				i++;

				// Bottom right.
				mParticelsContent[i].position = CPoint3F(item->pos.x + mpParticleEmitterType->mParticleSize.x, item->pos.y - mpParticleEmitterType->mParticleSize.y, item->pos.z);
				mParticelsContent[i].texture = CPoint2F(1.0f, 1.0f);
				mParticelsContent[i].color = item->color;
				i++;

				// Bottom right.
				mParticelsContent[i].position = CPoint3F(item->pos.x + mpParticleEmitterType->mParticleSize.x, item->pos.y - mpParticleEmitterType->mParticleSize.y, item->pos.z);
				mParticelsContent[i].texture = CPoint2F(1.0f, 1.0f);
				mParticelsContent[i].color = item->color;
				i++;

				// Top left.
				mParticelsContent[i].position = CPoint3F(item->pos.x - mpParticleEmitterType->mParticleSize.x, item->pos.y + mpParticleEmitterType->mParticleSize.y, item->pos.z);
				mParticelsContent[i].texture = CPoint2F(0.0f, 0.0f);
				mParticelsContent[i].color = item->color;
				i++;

				// Top right.
				mParticelsContent[i].position = CPoint3F(item->pos.x + mpParticleEmitterType->mParticleSize.x, item->pos.y + mpParticleEmitterType->mParticleSize.y, item->pos.z);
				mParticelsContent[i].texture = CPoint2F(1.0f, 0.0f);
				mParticelsContent[i].color = item->color;
				i++;
			}
			for (auto& item : mParticelsContent)
			{
				item.position.x += mPosition.x;
				item.position.y += mPosition.y;
				item.position.z += mPosition.z;
			}
		}
	}

	void CParticleEmitter::eEmitter(float fDeltaTime)
	{
		static float fTime = 0;
		fTime += fDeltaTime;
		if (fTime > mFrequency)
		{
			fTime -= mFrequency;
			mpParticleEmitterType->emitter();
		}

	}

}